﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;
using System.Windows.Interop;

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using System.Windows.Controls;

using Idlesoft.ShellAnywhere.Model;
using Idlesoft.DataStructures;

using Idlesoft.Interop;
using Idlesoft.Interop.Wpf;

namespace Idlesoft.ShellAnywhere.ViewModel
{
	public class ShellAnywhereViewModel : DependencyObject
	{
		#region consts
		public const string EMPTY_PROMPT = "";
		public const string SHELL_ANYWHERE_PROMPT = "ShellAnywhere>";
		public ShellActionViewModel EmptyShellActionViewModel { get { return new ShellActionViewModel(); } }
		#endregion consts

		#region ctors
		public ShellAnywhereViewModel()
		{
			ShellActions = new ObservableCollection<ShellActionViewModel>();
			OutputItems = new ObservableCollection<OutputItemsViewModel>();
			_Posture = Posture.Launch;
		}
		public ShellAnywhereViewModel(IShellAnywhereModel model) : this()
		{
			_Model = model;
			_Model.ShellActionsChanged += OnShellActionsChanged;
			_Model.OutputAppend += OnOutputAppend;
			_Model.ActionMgr.CurrentDirectoryChanged += OnCurrentDirectoryChanged;
			_Model.Init();
		}
		#endregion ctors

		#region props

		public string UserInput
		{
			get { return _Model.ActionMgr.UserInput; }
			set { _Model.ActionMgr.UserInput = value; }
		}
		private Posture _LastPosture;
		private Posture _Posture;
		public Posture Posture
		{
			get { return _Posture; }
			set
			{
				if (_Posture != value)
					OnPostureChanged(_Posture = value);
			}
		}
		public void OnPostureChanged(Posture posture)
		{
			_Model.Posture = posture;
			switch (posture)
			{
				case Posture.Hidden:
					WindowVisibility = Visibility.Hidden;
					_HiddenTime = DateTime.Now;
					Prompt = "";
					break;
				case Posture.Launch:
					OutputVisibility = Visibility.Collapsed;
					WindowVisibility = Visibility.Visible;
					Prompt = SHELL_ANYWHERE_PROMPT;
					OnShellActionsChanged();
					break;
				case Posture.Shell:
					WindowVisibility = OutputVisibility = Visibility.Visible;
					Prompt = SHELL_ANYWHERE_PROMPT;
					if (ResetColumns != null)
						ResetColumns();
					break;
				case Posture.Navigation:
					Prompt = CreatePrompt(_Model.ActionMgr.CurrentDirectory);
					_Model.ActionMgr.Update();
					break;
			}
		}
		private static readonly DependencyProperty WindowVisibilityProperty = DependencyProperty.Register("WindowVisibility", typeof(Visibility), typeof(ShellAnywhereViewModel), new UIPropertyMetadata(Visibility.Visible));
		public Visibility WindowVisibility
		{
			get { return (Visibility)GetValue(WindowVisibilityProperty); }
			set { SetValue(WindowVisibilityProperty, value); }
		}
		private static readonly DependencyProperty OutputVisibilityProperty = DependencyProperty.Register("OutputVisibility", typeof(Visibility), typeof(ShellAnywhereViewModel), new UIPropertyMetadata(Visibility.Collapsed));
		public Visibility OutputVisibility
		{
			get { return (Visibility)GetValue(OutputVisibilityProperty); }
			set { SetValue(OutputVisibilityProperty, value); }
		}
		private static readonly DependencyProperty PromptProperty = DependencyProperty.Register("Prompt", typeof(string), typeof(ShellAnywhereViewModel), new UIPropertyMetadata("ShellAnywhere>"));
		public string Prompt
		{
			get { return (string)GetValue(PromptProperty); }
			set { SetValue(PromptProperty, value); }
		}
		private static readonly DependencyProperty SelectedShellActionProperty = DependencyProperty.Register("SelectedShellAction", typeof(ShellActionViewModel), typeof(ShellActionViewModel), null);
		public ShellActionViewModel SelectedShellAction
		{
			get { return (ShellActionViewModel)GetValue(SelectedShellActionProperty); }
			set { SetValue(SelectedShellActionProperty, value); }
		}
		public ObservableCollection<ShellActionViewModel> ShellActions { get; set; }
		public ObservableCollection<OutputItemsViewModel> OutputItems { get; set; }
		#endregion props

		#region methods
		public void OnOutputAppend(Brush color, string text)
		{
			Posture = Posture.Shell;
			if (!string.IsNullOrEmpty(text) && OutputItems != null)
				OutputItems.Add(new OutputItemsViewModel(color, text));
		}
		private void OnKeyDown(object sender, KeyEventArgs e)
		{
			//set to true; if default switch reached it will be changed to false; e.Handled set afer the switch statment
			bool handled = true;
			try
			{
				switch (e.Key)
				{
					case Key.Escape:
						Posture = Posture.Hidden;
						break;
					case Key.Left:
					case Key.Back:
						_Model.ActionMgr.Withdraw();
						break;
					case Key.Right:
					case Key.Enter:
						if (_Model.ActionMgr.Advance())
							Posture = Posture.Hidden;
						break;
					case Key.Up:
						if (_Model.ActionMgr.HasActions)
							_Model.ActionMgr.Previous();
						else
							UserInput = _Model.HistoryMgr.DecrIndex();
						break;
					case Key.Down:
						if (_Model.ActionMgr.HasActions)
							_Model.ActionMgr.Next();
						else
							UserInput = _Model.HistoryMgr.IncrIndex();
						break;
					case Key.Tab:
						UserInput = _Model.ActionMgr.Complete();
						break;
					case Key.RightCtrl:
						Posture = (Posture == Posture.Launch) ? Posture.Shell : Posture.Launch;
						break;
					case Key.LeftCtrl:
						if (Posture == Posture.Launch || Posture == Posture.Shell)
						{
							_LastPosture = Posture;
							Posture = Posture.Navigation;
						}
						break;
					default:
						handled = false;
						break;
				}
				e.Handled = handled;
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.Message);
			}
		}
		private void OnTextComposition(object sender, TextCompositionEventArgs e)
		{
			//UserInput += e.Text;
			UserInput = "open crm"; //\0
			e.Handled = true;
		}
		private void OnKeyUp(object sender, KeyEventArgs e)
		{
			bool handled = false;
			switch (e.Key)
			{
				case Key.LeftCtrl:
					if (Posture == Posture.Navigation)
						Posture = _LastPosture;
					break;
			}
			e.Handled = handled;
		}
		private void OnPromptChanged(string prompt)
		{
			Prompt = prompt;
		}
		private void OnCurrentDirectoryChanged(string directory)
		{
			if (Posture == Posture.Navigation)
				Prompt = CreatePrompt(directory);
		}

		private void OnShellActionsChanged(List<IShellAction> shellActions = null, int index = 0)
		{
			ShellActions.Clear();
			if (shellActions == null || shellActions.Count == 0)
				ShellActions.Add(EmptyShellActionViewModel);
			else
			{

			}
		}
		public void OnSourceInitialized(object sender, EventArgs e)
		{
			OnShellActionsChanged();

			_ActiveSource = PresentationSource.FromVisual(sender as Visual);
			_KeyboardHook = new WpfKeyboardHook(_ActiveSource);
			_KeyboardHook.InstallHook();
			_KeyboardHook.KeyDown += OnKeyDown;
			_KeyboardHook.TextComposition += OnTextComposition;
			_KeyboardHook.KeyUp += OnKeyUp;
		}
		public void OnClosed(object sender, EventArgs e)
		{
			_ActiveSource = PresentationSource.FromVisual(sender as Visual);
			_KeyboardHook.KeyDown -= OnKeyDown;
			_KeyboardHook.TextComposition -= OnTextComposition;
			_KeyboardHook.KeyUp -= OnKeyUp;
			_KeyboardHook.UninstallHook();
			_Model.End();
		}
		private string CreatePrompt(string directory)
		{
			return "SA " + directory + ">";
		}
		#endregion methods

		#region events
		public event Action ResetColumns;
		//public event Action<List<ShellAction>, int> ShellActionsChanged;
		#endregion events

		#region fields
		delegate void OutputAppendDlg(string str, Brush color);

		private IShellAnywhereModel _Model;
		private PresentationSource _ActiveSource;
		private WpfKeyboardHook _KeyboardHook;

		private DateTime _HiddenTime;


		#endregion fields

	}
	//using ActionSet = Set<IAction>;
	//public class ShellAnywhereViewModel : DependencyObject
	//{
	//    #region empty
	//    public const string SHELL_ANYWHERE_PROMPT = "ShellAnywhere>";
	//    public const string EMPTY_PROMPT = "";
	//    public ActionViewModel EmptyActionViewModel { get { return new ActionViewModel(Prompt); } }
	//    #endregion empty

	//    #region ctors
	//    public ShellAnywhereViewModel()
	//    {
	//        Actions = new ObservableCollection<ActionViewModel>();
	//        Output = new ObservableCollection<OutputViewModel>();
	//        _Posture = Posture.Launch;
	//    }
	//    public ShellAnywhereViewModel(IShellAnywhereModel model) : this()
	//    {
	//        _Model = model;
	//        _Model.SetChanged += OnSetChanged;
	//        _Model.OutputAppend += OnOutputAppend;
	//        _Model.ActionMgr.CurrentDirectoryChanged += OnCurrentDirectoryChanged;
	//        _Model.Init();
	//    }
	//    ~ShellAnywhereViewModel()
	//    {
	//        _Model.End();
	//    }
	//    #endregion ctors

	//    #region props
	//    public string UserInput
	//    {
	//        get { return _Model.ActionMgr.UserInput; }
	//        set { _Model.ActionMgr.UserInput = value; }
	//    }
	//    private Posture _LastPosture;
	//    private Posture _Posture;
	//    public Posture Posture
	//    {
	//        get { return _Posture; }
	//        set
	//        {
	//            if (_Posture != value)
	//                OnPostureChanged(_Posture = value);
	//        }
	//    }
	//    public void OnPostureChanged(Posture posture)
	//    {
	//        _Model.Posture = posture;
	//        switch (posture)
	//        {
	//            case Posture.Hidden:
	//                WindowVisibility = Visibility.Hidden;
	//                _HiddenTime = DateTime.Now;
	//                Prompt = "";
	//                break;
	//            case Posture.Launch:
	//                OutputVisibility = Visibility.Collapsed;
	//                WindowVisibility = Visibility.Visible;
	//                Prompt = SHELL_ANYWHERE_PROMPT;
	//                OnSetChanged();
	//                break;
	//            case Posture.Shell:
	//                WindowVisibility = OutputVisibility = Visibility.Visible;
	//                Prompt = SHELL_ANYWHERE_PROMPT;
	//                if (ResetColumns != null)
	//                    ResetColumns();
	//                break;
	//            case Posture.Navigation:
	//                Prompt = CreatePrompt(_Model.ActionMgr.CurrentDirectory);
	//                _Model.ActionMgr.Update();
	//                break;
	//        }
	//    }

	//    public ObservableCollection<ActionViewModel> Actions { get; set; }
	//    public ObservableCollection<OutputViewModel> Output { get; set; }

	//    public Visibility WindowVisibility
	//    {
	//        get { return (Visibility)GetValue(WindowVisibilityProperty); }
	//        set { SetValue(WindowVisibilityProperty, value); }
	//    }
	//    public Visibility OutputVisibility
	//    {
	//        get { return (Visibility)GetValue(OutputVisibilityProperty); }
	//        set { SetValue(OutputVisibilityProperty, value); }
	//    }
	//    public string Prompt
	//    {
	//        get { return (string)GetValue(PromptProperty); }
	//        set { SetValue(PromptProperty, value); }
	//    }
	//    private static readonly DependencyProperty WindowVisibilityProperty = DependencyProperty.Register("WindowVisibility", typeof(Visibility), typeof(ShellAnywhereViewModel), new UIPropertyMetadata(Visibility.Visible));
	//    private static readonly DependencyProperty OutputVisibilityProperty = DependencyProperty.Register("OutputVisibility", typeof(Visibility), typeof(ShellAnywhereViewModel), new UIPropertyMetadata(Visibility.Collapsed));
	//    private static readonly DependencyProperty PromptProperty = DependencyProperty.Register("Prompt", typeof(string), typeof(ShellAnywhereViewModel), new UIPropertyMetadata("ShellAnywhere>"));
	//    #endregion props

	//    #region methods
	//    public void OnOutputAppend(Brush color, string text)
	//    {
	//        Posture = Posture.Shell;
	//        if (!string.IsNullOrEmpty(text) && Output != null)
	//            Output.Add(new OutputViewModel(color, text));
	//    }
	//    private void OnKeyDown(object sender, KeyEventArgs e)
	//    {
	//        //set to true; if default switch reached it will be changed to false; e.Handled set afer the switch statment
	//        bool handled = true;
	//        try
	//        {
	//            switch (e.Key)
	//            {
	//                case Key.Escape:
	//                    Posture = Posture.Hidden;
	//                    break;
	//                case Key.Left:
	//                case Key.Back:
	//                    _Model.ActionMgr.Withdraw();
	//                    break;
	//                case Key.Right:
	//                case Key.Enter:
	//                    if (_Model.ActionMgr.Advance())
	//                        Posture = Posture.Hidden;
	//                    break;
	//                case Key.Up:
	//                    if (_Model.ActionMgr.HasActions)
	//                        _Model.ActionMgr.Previous();
	//                    else
	//                        UserInput = _Model.HistoryMgr.DecrIndex();
	//                    break;
	//                case Key.Down:
	//                    if (_Model.ActionMgr.HasActions)
	//                        _Model.ActionMgr.Next();
	//                    else
	//                        UserInput = _Model.HistoryMgr.IncrIndex();
	//                    break;
	//                case Key.Tab:
	//                    UserInput = _Model.ActionMgr.Complete();
	//                    break;
	//                case Key.RightCtrl:
	//                    Posture = (Posture == Posture.Launch) ? Posture.Shell : Posture.Launch;
	//                    break;
	//                case Key.LeftCtrl:
	//                    if (Posture == Posture.Launch || Posture == Posture.Shell)
	//                    {
	//                        _LastPosture = Posture;
	//                        Posture = Posture.Navigation;
	//                    }
	//                    break;
	//                default:
	//                    handled = false;
	//                    break;
	//            }
	//            e.Handled = handled;
	//        }
	//        catch (Exception ex)
	//        {
	//            Debug.WriteLine(ex.Message);
	//        }
	//    }
	//    private void OnTextComposition(object sender, TextCompositionEventArgs e)
	//    {
	//        //UserInput += e.Text;
	//        UserInput = "open crm"; //\0
	//        e.Handled = true;
	//    }
	//    private void OnKeyUp(object sender, KeyEventArgs e)
	//    {
	//        bool handled = false;
	//        switch (e.Key)
	//        {
	//            case Key.LeftCtrl:
	//                if (Posture == Posture.Navigation)
	//                    Posture = _LastPosture;
	//                break;
	//        }
	//        e.Handled = handled;
	//    }
	//    private void OnPromptChanged(string prompt)
	//    {
	//        Prompt = prompt;
	//    }
	//    private void OnCurrentDirectoryChanged(string directory)
	//    {
	//        if (Posture == Posture.Navigation)			
	//            Prompt = CreatePrompt(directory);
	//    }
	//    private void OnSetChanged(ActionSet set = null)
	//    {
	//        Actions.Clear();
	//        if (set == null || set.Count == 0)
	//            Actions.Add(EmptyActionViewModel);
	//        else
	//        {
	//            int dot = set.Dot;
	//            IAction current = set.CurrentItem;
	//            for (int index = 0; index < set.Count; ++index)
	//            {
	//                IAction child = set.Items[index];
	//                if (current == child)
	//                    Actions.Add(new ActionViewModel(Prompt, child, dot));
	//                else
	//                    Actions.Add(new ActionViewModel(EMPTY_PROMPT, child, dot));
	//            }
	//        }
	//    }
	//    public void OnSourceInitialized(object sender, EventArgs e)
	//    {
	//        OnSetChanged();

	//        _ActiveSource = PresentationSource.FromVisual(sender as Visual);
	//        _KeyboardHook = new WpfKeyboardHook(_ActiveSource);
	//        _KeyboardHook.InstallHook();
	//        _KeyboardHook.KeyDown += OnKeyDown;
	//        _KeyboardHook.TextComposition += OnTextComposition;
	//        _KeyboardHook.KeyUp += OnKeyUp;
	//    }
	//    public void OnClosed(object sender, EventArgs e)
	//    {
	//        _ActiveSource = PresentationSource.FromVisual(sender as Visual);
	//        _KeyboardHook.KeyDown -= OnKeyDown;
	//        _KeyboardHook.TextComposition -= OnTextComposition;
	//        _KeyboardHook.KeyUp -= OnKeyUp;
	//        _KeyboardHook.UninstallHook();
	//        _Model.End();
	//    }
	//    private string CreatePrompt(string directory)
	//    {
	//        return "SA " + directory + ">";
	//    }
	//    #endregion methods
				
	//    #region events
	//    public System.Action ResetColumns;
	//    #endregion events

	//    #region fields
	//    delegate void OutputAppendDlg(string str, Brush color);

	//    private IShellAnywhereModel _Model;
	//    private PresentationSource _ActiveSource;
	//    private WpfKeyboardHook _KeyboardHook;

	//    private DateTime _HiddenTime;
	//    #endregion fields
	//}
}
